package pl.edu.agh.gt.ga.greedy;

import java.io.File;
import java.io.IOException;
import java.util.Date;

import org.apache.log4j.Logger;

import pl.edu.agh.gt.Stock;
import pl.edu.agh.gt.data.DataProvider;
import pl.edu.agh.gt.data.RatesHistory;
import pl.edu.agh.gt.ga.FitnessFunction;
import pl.edu.agh.gt.ga.Genotype;
import pl.edu.agh.gt.ga.Parameters;
import pl.edu.agh.gt.gui.ChartDisplay;
import pl.edu.agh.gt.stock.Trader;
import pl.edu.agh.gt.strategy.BuyAndHold;
import pl.edu.agh.gt.strategy.GreedyStrategy;
import pl.edu.agh.gt.strategy.Strategy;

public class FitnessFunctionImpl implements FitnessFunction {

	private final static Logger log = Logger.getLogger(FitnessFunctionImpl.class);

	private final RatesHistory rates;

	public FitnessFunctionImpl() throws IOException {

		@SuppressWarnings("deprecation")
		Date start = new Date(2011 - 1900, 2, 7); // 7 // 11 // 7

		@SuppressWarnings("deprecation")
		Date end = new Date(2011 - 1900, 2, 18); // 18 downup // 23 rosnacy //
													// 11 malejacy

		log.info("Using stock period " + start + " to " + end);

		rates = DataProvider.readData(
				new File("src/main/resources/EURUSD_hour.csv")).getPeriod(
				start, end);
	}

	@Override
	public float estimate(Genotype genotype, Parameters params) {

		GreedyStrategy strategy = decode(genotype);
		float fitness = 0;
		try {
			
			log.debug("Analizing strategy: " + strategy);

			final Stock stock = new Stock(rates);
			final Trader trader = new Trader("TraderX", stock, strategy);
			stock.addTrader(trader);

			stock.runStock();

			float traderValue = trader.evaluate(stock.getRatesHistory()
					.getLastRate());
			fitness = (traderValue - Trader.INITIAL_VALUE) / trader.maxInvested;

			log.debug("Stock simulation finished, trader total:" + traderValue
					+ ", maxInvested: " + trader.maxInvested);
			log.debug("FITNESS = " + fitness);

		} catch (Exception e) {
			log.error("Stock exception", e); // XXX wrap & throw
		}

		return fitness;
	}

	public void showGenotypeTradingComparedToBuyAndHold(Genotype genotype) {

		// Logger.getLogger("pl.edu.agh.gt.strategy").setLevel(Level.DEBUG);
		// Logger.getLogger("pl.edu.agh.gt.stock").setLevel(Level.DEBUG);
		Stock stock = new Stock(rates);

		Strategy strategy = decode(genotype);
		Trader trader1 = new Trader("Greedy", stock, strategy);
		trader1.setLogTrading(true);
		stock.removeTraders();
		stock.addTrader(trader1);
		stock.runStock();

		log.info("Trader: maxInvested = " + trader1.maxInvested
				+ ", \ttotalWorth: " + (trader1.baseCurrency-Trader.INITIAL_VALUE)
				+ ", \tbuy actions: " + trader1.buyActions + ", \tsell actions: "
				+ trader1.sellActions + ", \tclose actions: "
				+ trader1.closeActions);

		BuyAndHold bAndH = new BuyAndHold();
		bAndH.initialInvestment = Math.min(trader1.maxInvested,
				Trader.INITIAL_VALUE);
		Trader trader2 = new Trader("Buy&Hold", stock, bAndH);
		trader2.setLogTrading(true);
		stock.removeTraders();
		stock.addTrader(trader2);
		stock.runStock();

		ChartDisplay.tradingChart("Strategy " + strategy, stock.getRatesHistory(),
				trader1.getTradingHistory(), trader2.getTradingHistory());
	}

	public static GreedyStrategy decode(Genotype genotype) {

		GreedyStrategy strategy = new GreedyStrategy();

		// strategy.resolution = (Integer) genotype.getGene("resolution");
		strategy.greedA = (Float) genotype.getGene("greedA");
		// strategy.greedB = (Float) genotype.getGene("greedB");
		strategy.maxLoss = (Float) genotype.getGene("maxLoss");
		strategy.desiredEarn = (Float) genotype.getGene("desiredEarn");
		strategy.enteringValue = (Float) genotype.getGene("enteringValue");
		strategy.lossTolerancy = (Float) genotype.getGene("lossTolerancy");

		return strategy;
	}
}
